package work.xiaohong.search.controller;

import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.core.TimeValue;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import work.xiaohong.search.config.ElasticsearchConfig;
import work.xiaohong.search.entity.Result;
import work.xiaohong.search.entity.StatusCode;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;

@RequestMapping("/search")
@RestController
public class SearchController {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Autowired
    private IndexController indexController;

    /**
     * 查询指定索引下所有文档
     * @param index
     * @return
     */
    @GetMapping("/{index}")
    public Result searchAll(@PathVariable(name = "index") String index) throws Exception {
        SearchRequest searchRequest = new SearchRequest(index);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.matchAllQuery());
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, ElasticsearchConfig.COMMON_OPTIONS);

        return responsHandle(searchResponse);
    }

    /**
     * 按字段搜索
     * @param index
     * @return
     */
    @PostMapping("/term/{index}")
    public Result termSearchPost(@PathVariable(name = "index") String index,
                         @RequestParam(name = "lights",required = false) List<String> lights,
                         @RequestBody Map<String,String> terms) throws Exception {

        if (terms == null){
            return searchAll(index);
        }

        SearchRequest searchRequest = new SearchRequest(index);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        for (String s : terms.keySet()) {
            searchSourceBuilder.query(QueryBuilders.termQuery(s, terms.get(s)));
        }


        // 高亮搜索
        if(lights != null && lights.size() > 0){
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            for (String light : lights) {
                highlightBuilder.field(light);//想要的高亮字段
            }
            highlightBuilder.preTags("<span style='color:red'>");//前缀
            highlightBuilder.postTags("</span>");//后缀
            searchSourceBuilder.highlighter(highlightBuilder);
        }

        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, ElasticsearchConfig.COMMON_OPTIONS);



        return responsHandle(searchResponse);
    }


    /**
     * 按字段搜索
     * @param index
     * @return
     */
    @GetMapping("/term/{index}")
    public Result termSearchGet(@PathVariable(name = "index") String index, HttpServletRequest httpServletRequest) throws Exception {

        SearchRequest searchRequest = new SearchRequest(index);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        // 高亮搜索
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("message");//想要的高亮字段
        highlightBuilder.preTags("<span style='color:red'>");//前缀
        highlightBuilder.postTags("</span>");//后缀
        searchSourceBuilder.highlighter(highlightBuilder);

        // 获取请求参数
        Map<String, String[]> parameterMap = httpServletRequest.getParameterMap();

        for (String s : parameterMap.keySet()) {
            if("key".equals(s)){
                // 关键字查询
                searchSourceBuilder.query(QueryBuilders.multiMatchQuery(parameterMap.get(s)[0],"id","message"));
            }else{
                // 查询字段
                searchSourceBuilder.query(QueryBuilders.termQuery(s, parameterMap.get(s)[0]));
            }
        }


        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, ElasticsearchConfig.COMMON_OPTIONS);



        return responsHandle(searchResponse);
    }

    public Result responsHandle(SearchResponse searchResponse){
        if(!RestStatus.OK.equals(searchResponse.status())){
            return new Result(false, StatusCode.ERROR,"搜索状态异常，搜索失败");
        }

        if(searchResponse.isTerminatedEarly() != null && !searchResponse.isTerminatedEarly()){
            return new Result(false, StatusCode.ERROR,"搜索提前终止，搜索失败");
        }

        if(searchResponse.isTimedOut()){
            return new Result(false, StatusCode.ERROR,"搜索超时，搜索失败");
        }

        TimeValue took = searchResponse.getTook(); //搜索耗时

//        SearchHits hits = searchResponse.getHits();
//        TotalHits totalHits = hits.getTotalHits();
//        long numHits = totalHits.value; // 总命中数
//        TotalHits.Relation relation = totalHits.relation;
//        float maxScore = hits.getMaxScore(); // 命中最大得分

        // 结果集合
        SearchHit[] searchHits = searchResponse.getHits().getHits();

        //解析高亮结果  将高亮部分替换原来的数据
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            //获取高亮属性,这里如果看过kibana中的高亮的返回结果的话应该很好理解
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            HighlightField title = highlightFields.get("message");
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();//原来的结果
            //解析高亮的字段，将原来的字段换位我们高亮的字段即可
            if(title != null){
                Text[] fragments = title.fragments();
                String n_title = "";
                for (Text text : fragments) {
                    n_title += text;
                }
                sourceAsMap.put("message", n_title);
            }
        }



        return new Result(true, StatusCode.OK,"搜索成功",searchResponse.getHits().getHits());

    }

}
